﻿using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Data.Common;
using System.Data.Entity;
using System.Data.Entity.Infrastructure.Interception;
using System.Data.SqlClient;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using EntityFrameworkETL.DynamicLinq;
using EntityFrameworkETL.Interceptors;
using EntityFrameworkETL.SaveBatchedChanges;

namespace EntityFrameworkETL.Extensions
{
    public static class DbContextExtensions
    {
        public static int SaveBatchedChanges(this DbContext dbContext, IFakeReaderGenerator fakeReaderGenerator = null,
            ICommandParser commandParser = null, ICommandDbContextSync commandDbContextSync = null,
            ICommandCacheStructurer commandCacheStructurer = null, IBatchCommands batchCommands = null,
            IExecuteBatchedCommand executeBatchedCommand = null, IFixupCommands fixupCommands = null)
        {
            if (fakeReaderGenerator == null) fakeReaderGenerator = new FakeReaderGenerator();
            if (commandParser == null) commandParser = new CommandParser();
            if (commandDbContextSync == null) commandDbContextSync = new CommandDbContextSync();
            if (commandCacheStructurer == null) commandCacheStructurer = new CommandCacheStructurer();
            if (batchCommands == null) batchCommands = new BatchCommands();
            if (executeBatchedCommand == null) executeBatchedCommand = new ExecuteBatchedCommand();
            if (fixupCommands == null) fixupCommands = new FixupCommands();

            var commandCaches = dbContext.GetCommandCaches(fakeReaderGenerator);
            commandCaches.ToList().ForEach(x =>
            {
                x.TableName = commandParser.ParseTableName(x.DbCommand);
                x.ParameterIsFkDictionary = commandParser.ParseFkParameters(x.DbCommand);
            });
            commandDbContextSync.Sync(dbContext, commandCaches);
            var structuredCommandCaches = commandCacheStructurer.GeStructuredCommandCaches(commandCaches);
            var batchedCommands = batchCommands.BatchAndExecute(dbContext, structuredCommandCaches, executeBatchedCommand, fixupCommands);

            
            return structuredCommandCaches.Count();
        }

        public static IEnumerable<CommandCache> GetCommandCaches(this DbContext dbContext, IFakeReaderGenerator fakeReaderGenerator)
        {
            var interceptor = new CommandCacheInterceptor(fakeReaderGenerator);
            DbInterception.Add(interceptor);
            dbContext.Configuration.AutoDetectChangesEnabled = false;
            dbContext.SaveChanges();
            DbInterception.Remove(interceptor);
            return interceptor.CommandCaches;
        }
    }
}
